/*
 * \file sofs_ifuncs_2.c
 * \author Diogo Pinheiro
 * \date September, 2008
 * 
 * This file implements the set of functions to manipulate SOFS08 file system's inodes
 *
 * \remarks In case an error occurs all functions return a negative 
 *      value, which is the symmetric of the system error that
 *      better represent the error cause.
 *      (Execute command <e>man errno</e>, for details.)
 */
#include "sofs_ifuncs.h"

#include "sofs_const.h"
#include "sofs_probe.h"
#include "sofs_buffercache.h"
#include "sofs_superblock.h"
#include "sofs_inode.h"

#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>            /* for memcpy() and memset() */
#include <time.h>



/**
 * \brief Write a file's data block to disk.
 *
 * \param in number of the file's inode
 * \param bn number of the block to be read
 * \param buf pointer to buffer
 * 
 * \details
 * Write data from buffer pointed to by buf to block number bn
 * of the file (of any type) associated with inode number in.
 * Value of bn represents a relative block number within the file: bn is 0 (zero) for
 * the first block of data, 1 (one) for the second, and so on.
 *
 * Difficulty level: 3
 *
 * \return 0 on success and an appropriated negative value on error:
 */
int soWriteFileBlock(u_int32_t in, u_int32_t bn, void *buf)
{

	/* TODO
	 * O bloco máximo a que pode aceder é dado pelo campo size ou pelo campo count ?
	 * O que acontece se o bloco que está a tentar ler estiver vazio ?
	 * Confirmar se o inode recebido é válido ?
	 * É preciso confirmar permissões ?
	 *
	 */

	SOInode *inodein;

	int ret;

	/* ler o inode pretendido */
	if ((ret=soReadInode(inodein, in)) < 0) return ret;

	/* bloco com o offset bn */
	u_int32_t blockn;

	/* verificar se não está a tentar aceder a um bloco que não faz parte do ficheiro */
	if(bn >= ((inodein->counts) & 0xFFFFFF))
		return -EINVAL;

	
	if (bn>=48)
		/* offset inválido */
		return -EINVAL;
	else
		if (bn>=0 && bn<6) 
			/* encontra-se nas referencias directas */
			blockn = inodein->d[bn];
		else
		{
			u_int32_t blockaux[RPB];

			if (bn>=6 && bn<6+RPB) 
			{
				/* encontra-se nas referencias indirectas */
				/* ler o bloco apontado por i1 */
				if((ret=soReadCacheBlock((inodein->i1), blockaux)) < 0) 
					return ret;
	
				blockn = blockaux[bn-6];
			}
			else
			{
				/* encontra-se nas referencias duplamente indirectas */
				bn = bn-6-RPB;
				/* ler o bloco apontado por i2 */
				if((ret=soReadCacheBlock((inodein->i2), blockaux)) < 0) 
					return ret;
				
				/* ler o bloco apontado por blockaux */
				if((ret=soReadCacheBlock(blockaux[bn/RPB], blockaux)) < 0) 
					return ret;

				blockn = blockaux[bn%RPB];
			}
		}




	/* escrever no bloco o conteudo de buf */
	if((ret=soWriteCacheBlock(blockn, buf)) < 0) return ret;

	return 0;

}


